//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/stat.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <sys/types.h>

#include <unistd.h>
#include <fcntl.h>

#include <time.h>
#include <errno.h>

#include "rutines.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main (int argc, char** argv) {
  
  int       pidFork;
  int       i;
  int       sig;
  int       noend;
  int       x;
  int       counter;
  int       file;
  int       fileOut;

  char      buffer [MAXSTR];
    
  if (argc < 4) 
    error("Missing Arguments (./clusterHugeDB <input ID cluster file> <input smi file> <out file - new smi file>");

  for (i = 0; i < argc; i++) 
    if (!memcmp(argv[i], "fast", strlen("fast"))) 
      mode = MODE_FAST;
  
  blockSize   = atoi(argv[3]);
  blockArgv   = argv[3];
  namefileOut = argv[2];
  
  fileOut = open (namefileOut, O_CREAT | O_WRONLY | O_TRUNC, 0644);
  close(fileOut);

  for (i = 0; i < MAX_CONCURRENT_PROCESS; i++) {
    
    if (pipe(pipes[i]) < 0)
      error("Error in pipe");
    
    switch (pidFork = fork()) {
      
      case -1 : error("Error in fork");
      
      case  0 : dup2(pipes[i][0], STDIN_FILENO);
                sprintf(buffer, "%d.dat", getpid());
                unlink(buffer);
                file = open(buffer, O_CREAT | O_WRONLY | O_TRUNC, 0644);
                dup2(file, STDOUT_FILENO);
                close(file);
                
                close(pipes[i][0]);
                close(pipes[i][1]);
                
                if (mode == MODE_FAST)
                  execl("./computeCluster", "./computeCluster", argv[3], "fork", "fast", (char *)0);
                else
                  execl("./computeCluster", "./computeCluster", argv[3], "fork", (char *)0);
                
                error("Error in execl");
      
      default : close(pipes[i][0]);
      
                pidsArray[forkProcess++] = pidFork; 
                sigemptyset(&signalVar);
                sigaddset(&signalVar, SIGUSR1);
                sigprocmask(SIG_BLOCK, &signalVar, NULL);
                sigwait(&signalVar, &sig);
                sigprocmask(SIG_UNBLOCK, &signalVar, NULL);
                
                break;
                
    }
    
  }
  
  sigemptyset(&signalVar); 
  sigaddset(&signalVar, SIGCHLD);
  sigprocmask(SIG_BLOCK, &signalVar, NULL);
  
  if ((inputFile = open(argv[1], O_RDONLY)) < 0)
    error("Error in open");
  
  for (i = 0, counter = 0, noend = 1; i < MAX_CONCURRENT_PROCESS; i++) {
    
    if (!noend) { kill(pidsArray[i], SIGKILL); continue; }
    
    do {
      
      if (counter++ >= blockSize) { counter = 0; break; }
    
      x = 0;
      
      while ((noend = read(inputFile, &buffer[x], 1)) == 1 && buffer[x++] != '\n');
      if (!noend) { status = 0; break; }
      
      buffer[x] = '\0';
      
      if (write(pipes[i][1], buffer, strlen(buffer)) < 0)
        error("Error in write");
      
    } while (noend);
    
    close(pipes[i][1]);
    
  }
  
  sigprocmask(SIG_UNBLOCK, &signalVar, NULL);

  if (forkProcess) 
    while (1) {
      if (!forkProcess) break;
      pause();
    }
  
  close(inputFile);
  return EXIT_SUCCESS;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//

